﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using HidDevice;
using System.Threading;
using System.IO;
using Microsoft.Win32;

namespace HIDTOOL
{
      

    public partial class mianForm : Form
    {
        string CurrVer = "V1.3.4";

        frm_Setting Setting;        //设置的窗口        
        Hid HID = new Hid();
        public string HID_Dir = null;
        public mianForm()
        {
            InitializeComponent();
            //Close();

            Control.CheckForIllegalCrossThreadCalls = false;//允许跨线程使用控件
            Setting = new frm_Setting(this);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                RegistryKey reg = Registry.CurrentUser.CreateSubKey("SoftWare\\HIDtool");
                int x = Convert.ToInt32(reg.GetValue("WinX"));
                int y = Convert.ToInt32(reg.GetValue("WinY"));
                int W = Convert.ToInt32(reg.GetValue("WinW"));
                int H = Convert.ToInt32(reg.GetValue("WinH"));
                
                
                this.Location = new Point(x, y);//可以转换成 Left 、Top 见 2.
                this.Width = W;
                this.Height = H;
            }
            catch 
            {}

            HID.DataReceived = HidDataReceived;     //HID数据接收委托，委托赋值 用HidDataReceived函数
            HID.DeviceRemoved = HidDeviceRemoved;   //HID设备拔出
            HID_Dir = Setting.MySetting.HID_Dir;
            if (HID_Dir == "")
            {
                btn_OpenHid.Enabled = false;
                lbl_PID.Hide();
                lbl_VID.Hide();
            }
            else
            {
                lbl_VID.Text = HID_Dir.Substring(12, 4).ToUpper();        //提取 HID设备地址的vID //HID范例地址：	\\?\hid#vid_1111&pid_0003#8&2f34cf51&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
                lbl_PID.Text = HID_Dir.Substring(21, 4).ToUpper();       //提取 HID设备地址的pID
            }
            this.Text = "HID数据收发工具 " + CurrVer;

            
            ////*****读取设置文件，改变界面控件**************************
            chk_HexShow.Checked = Setting.MySetting.HexShow;
            chk_HexSend.Checked = Setting.MySetting.HexSend;
            SettingLoadOK = true;

            //*******鼠标悬浮气泡提示**********************
            ToolTip ttpSettings = new ToolTip();
            string tipOverwrite ="左键：清空接收区；右键：清空发送计数器";
            ttpSettings.SetToolTip(btn_ClearRX, tipOverwrite);
        }



        private void 选择HID设备ToolStripMenuItem_Click(object sender, EventArgs e)     //菜单栏的 选择HID设备
        {
            frm_HidSelect Form_HidSelect = new frm_HidSelect(this);
            Form_HidSelect.ShowDialog();
        }

        /// <summary>
        /// 下面是打开HID设备的函数
        /// </summary>
        public bool Hid_isConnected = false; 
        public void btn_OpenHid_Click(object sender, EventArgs e)  //点击连接按钮
        {
            if (btn_OpenHid.Text == "连接")       //HID没有连接
            {
                if (HID_Dir != null)
                {
                    Hid.HID_RETURN ret = Open_HID();
                    if (ret == Hid.HID_RETURN.SUCCESS)
                    {
                        StartShowThr();                     //HID打开成功：启动显示线程
                        StartSendThr();                     //HID打开成功：启动发送线程
                        btn_OpenHid.Text = "断开";
                        Hid_isConnected = true;
                        lbl_status.Text = "已连接";
                        lbl_status.ForeColor = Color.ForestGreen;
                        btn_OpenHid.BackColor = Color.GreenYellow;
                    }
                    else
                        MessageBox.Show("设备打开失败！\r\n请检查设备是否连接正常","提示");
                }
            }
            else if(btn_OpenHid.Text == "断开")       //HID连接
            {
                Thread_Show_EXIT = true;    //需要退出显示线程
                Thread_Send_EXIT = true;    //需要退出发送线程
                btn_OpenHid.Text = "连接";
                lbl_status.Text = ("已断开");
                lbl_status.ForeColor = Color.Red;
                btn_OpenHid.BackColor = SystemColors.Control;       //按键颜色回复默认
                HID.CloseDevice();
                Hid_isConnected = false; 
            }
        }

        public Hid.HID_RETURN Open_HID()///给 选择窗口调用的函数,  用于打开HID设备
        {
            Setting.NeedSaveSetting = true;
            if (Hid_isConnected == true)    //点击连接时候，HID已经连接，则先断开
            {
                btn_OpenHid_Click(null , null);
                Thread.Sleep(100);
            }
            return HID.OpenDevice(HID_Dir);
        }

        /// <summary>
        /// HID设备移除的 服务函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void HidDeviceRemoved(object sender, EventArgs e)//设备移除
        {
            //MessageBox.Show("设备移除");
            lbl_status.Text = "设备断开"; lbl_status.ForeColor = Color.Red;
            btn_OpenHid.Text = "连接";
            btn_OpenHid.BackColor = SystemColors.Control;       //按键颜色回复默认
            Hid_isConnected = false;
            Thread_Show_EXIT = true;

            if (HID != null)
            {
                HID.CloseDevice();
            }
        }

        /// <summary>
        /// 数据接收 的服务函数
        /// </summary>
        byte[] ReceiveBuff = new byte[64];
        bool Data_isReceived = false;
        public void HidDataReceived(object sender, report e)//收到数据会进入这里，这是 的处理器/方法
        {
            try
            {
                //MessageBox.Show("RX");
                //第一个字节为数据长度，因为Device 的HID数据固定长度为64字节，取有效数据
                byte[] buf = new byte[64];
                Array.Copy(e.reportBuff, 0, ReceiveBuff, 0, 64);
                Data_isReceived = true;
                //StartShowThr();                     //HID打开成功：启动显示线程
            }
            catch
            {
                MessageBox.Show("Receive Error");
                Data_isReceived = false;
                return;
            }
        }
//***************************显示线程*********************
        /// <summary>
        /// 打开HID后，启动一个线程，实时监测有没有数据被接收，如果有，则显示出来
        /// </summary>
        Thread Thread_Show;             //显示线程
        bool Thread_Show_EXIT = false;  //需要退出显示线程
        public void StartShowThr()
        {
            Thread_Show_EXIT = false;
            Thread_Show = new Thread(show_Thr);
            Thread_Show.Priority = ThreadPriority.Normal;
            Thread_Show.Start();
        }

        UInt32 RxNum = 0;
        UInt32 FameNum = 0;
        private void show_Thr()        //被启动的 show 线程
        {
            while (Thread_Show_EXIT == false)
            {
                if (Data_isReceived == true)        
                {
                    if (Setting.MySetting.ClearAtNFrame != 0)        //N 帧后清空，非0 
                    {
                        if (FameNum >= Setting.MySetting.ClearAtNFrame)
                            btn_ClearRX_Click(null, null);
                    }

                    StringBuilder showtxt = new StringBuilder();
                    Data_isReceived = false;
                    if (chk_HexShow.Checked == true)    //十六进制显示
                    {                      
                        ////显示数据                        
                        for (byte i = 0; i < Setting.MySetting.ShowNByte; i++)                        
                            showtxt.Append(string.Format("{0:X2} ", ReceiveBuff[i]));
                        if(Setting.MySetting.ShowNByte < 64)
                            showtxt.Append("...  ");
                    }
                    else    //文本显示
                    {
                        showtxt.Append(System.Text.Encoding.Default.GetString(ReceiveBuff).Trim('\0'));
                    }
                    if (Setting.MySetting.NextlineEveryFrame)       //每一帧换行  直接访问会有警告，可以改用方法访问
                        showtxt.Append("\r\n");

                    txt_ShowRX.Text += showtxt;                        
                    txt_ShowRX.Select(txt_ShowRX.TextLength, 0);//光标定位到文本最后     
                    txt_ShowRX.ScrollToCaret();//滚动到光标处
                   
                    RxNum += 64;
                    FameNum++;
                    Ssrlbl_RxNum.Text = RxNum.ToString();
                }
         
                //Thread.Sleep(1);                
            }
        }



//*****************发送的HEX  与 字符 转换选择*******************************
        /// <summary>
        /// 下面是发送数据，只发送 64字节
        /// </summary>
        /// <param name="ASCIIx"></param>
        /// <returns></returns>
        private byte ASCII2HEX(char ASCIIx)//ASCII的 '0' ~ 'F' 转 0x0 ~ 0xF
        {
            if (ASCIIx >= 0x30 && ASCIIx <= 0x39)   // 0 ~ 9
                return ((byte)(ASCIIx - 0x30));
            else if (ASCIIx >= 'A' && ASCIIx <= 'Z')   // A ~ Z
                return ((byte)(ASCIIx - 55));
            else if (ASCIIx >= 'a' && ASCIIx <= 'z')   // a ~ z
                return ((byte)(ASCIIx - 87));
            else
                return 0x80;
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        UInt32 SendNum = 0;
        int thisTimeTXLen = 0;  //本次发送实际字节数
        byte[] TxBuff = null;
        private void btn_Send_Click(object sender, EventArgs e)                                 //点击发送按钮
        {
            if (Hid_isConnected == false)    // HID设备关闭
            {
                if (HID_Dir == null)                            //没有选择好 HID 设备
                {
                    MessageBox.Show("请先选择HID设备", "提示");
                    选择HID设备ToolStripMenuItem_Click(null, null);
                    return;
                }
                else if(HID_Dir != null)                            //选择好 HID 设备，
                {
                    //MessageBox.Show("请先连接HID设备", "提示");
                    btn_OpenHid_Click(null, null);
                    if (Hid_isConnected)
                        btn_Send_Click(null, null);
                    return;
                }
            }
 
            else if(txt_Send.Text == "")
            {
                MessageBox.Show("发送框内没有数据", "提示");                
                return;
            }
            int Textlen = txt_Send.Text.Length;   //发送框文本长度。一个汉字被识别为 1
            TxBuff = new byte[Textlen];
            
            if (chk_HexSend.Checked == true)  //勾选“16进制发送”
            {               
                //string Txbuff = SendText.Text;
                //Txbuff.ToUpper();
                byte[] Buff = new byte[Textlen];    //变成16进制中间缓存
                int BuffLen = 0;
                
                int TxBuffLen = 0;
                for (int i = 0; i < Textlen; i++)       //去掉输入数据中的空格和其他字符,只保留ASCII码，存在Buff中
                {
                    byte temp = ASCII2HEX(txt_Send.Text[i]);
                    if (temp <= 0x0f)
                    {
                        Buff[BuffLen] = temp;
                        BuffLen++;
                    }
                }
                if (BuffLen % 2 != 0)
                    BuffLen--;
                for (int i = 0; i < BuffLen; i += 2)
                {
                    TxBuff[TxBuffLen] = (byte)((Buff[i] << 4) + Buff[i + 1]);
                    TxBuffLen++;
                }
                thisTimeTXLen = TxBuffLen;                
            }
            else                            //字符串发送
            {
                //编码转换：****发送发送框的内容，支持中文gb2312（高在前）****可以改为Unicode（低位在前）*****************
                Encoding str = System.Text.Encoding.GetEncoding("gb2312");

                //编码转换：****发送发送框的内容，支持中文utf8*********************
                //System.Text.UTF8Encoding str = new System.Text.UTF8Encoding();

                //****发送数据*************************
                byte[] Tobytes = str.GetBytes(txt_Send.Text);
                Array.Copy(Tobytes, TxBuff, Tobytes.Length);
                thisTimeTXLen = Tobytes.Length;    
            }
            //HID.Send64Bytes(TxBuff);
            //HID.SendNBytes(TxBuff, thisTimeTXLen);
            NeedSend = true;
            SendNum += (UInt32)thisTimeTXLen;       //累加 发送数据量
            Ssrlbl_SendNum.Text = SendNum.ToString();     
        }

//*****************************************************************************发送线程*****************************
        /// <summary>
        /// 打开HID后，启动一个线程，实时监测有没有数据被接收，如果有，则显示出来
        /// </summary>
        Thread Thread_Send;             //发送线程
        bool NeedSend = false;          //有数据需要发送
        bool Thread_Send_EXIT = false;  //需要退出发送线程
        public void StartSendThr()
        {
            Thread_Send_EXIT = false;
            Thread_Send = new Thread(Send_Thr);
            Thread_Send.Priority = ThreadPriority.Normal;
            Thread_Send.Start();
        }

        private void Send_Thr()        //被启动的 Send 线程
        {
            while (Thread_Send_EXIT == false)
            {
                if (NeedSend == true && TxBuff != null)
                {
                    NeedSend = false;
                    btn_Send.Enabled = false;

                    if (thisTimeTXLen <= 64)   //本次发送实际字节数)
                        HID.Send64Bytes(TxBuff);
                    else
                    {
                        byte[] SendArray = new byte[64];
                        int N64B = (thisTimeTXLen / 64);     //要发的数据是 64 的这么多倍
                        int OverN64B = (thisTimeTXLen % 64);     //要发的数据发N次64 后剩余这么多单独发送
                        int AddrOfdat = 0;
                           
                        for (int i = 0; i < N64B; i++)
                        {
                            Array.Copy(TxBuff, AddrOfdat, SendArray, 0, 64);
                            AddrOfdat += 64;
                            HID.Send64Bytes(SendArray);//默认[0]是字节数，[1]~[64]是有效数据                            
                            Thread.Sleep(2);
                        }
                        SendArray = null;
                        if (OverN64B > 0)
                        {
                            byte[] SendArrayOver = new byte[64];
                            Array.Copy(TxBuff, AddrOfdat, SendArrayOver, 0, OverN64B);
                            HID.Send64Bytes(SendArrayOver);//默认[0]是字节数，[1]~[64]是有效数据
                            SendArrayOver = null;
                        }
                    }
                    
                    TxBuff = null;
                    btn_Send.Enabled = true;
                }                
                Thread.Sleep(1);                
            }
        }


//**************************************************************************************************其他事件************************
        private void btn_ClearRX_Click(object sender, EventArgs e)      //清空
        {
            txt_ShowRX.Text = "";
            RxNum = 0;
            FameNum = 0;
            Ssrlbl_RxNum.Text = "0";
        }

        private void FormCloseing(object sender, FormClosingEventArgs e)//窗口关闭 中 事件
        {
            e.Cancel = true;
            Thread_Show_EXIT = true;
            Thread_Send_EXIT = true;    //需要退出发送线程
            if (Hid_isConnected == true)
                HID.CloseDevice();
            if (Setting.NeedSaveSetting == true) 
            {
                Setting.SettingFile_Write();
            }

            try
            {
                //-----退出前保存数据--------------------------
                RegistryKey reg1 = Registry.CurrentUser;
                RegistryKey reg2 = reg1.CreateSubKey("SoftWare\\HIDtool");
                reg2.SetValue("WinX", this.Location.X);
                reg2.SetValue("WinY", this.Location.Y);
                reg2.SetValue("WinW", this.Width);
                reg2.SetValue("WinH", this.Height);
            }catch{}


            e.Cancel = false;
            Environment.Exit(0);
        }

        private void 关于ToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            About AboutFrom = new About();
            AboutFrom.ShowDialog();
        }

        private void 查看新版本ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CheckUpdate Form_CheckUpdate = new CheckUpdate(CurrVer);
            Form_CheckUpdate.ShowDialog();
        }



        bool SettingLoadOK = false;
        private void chk_HexShow_Send_CheckedChanged(object sender, EventArgs e)
        {
            if (SettingLoadOK == true)
            {
                Setting.MySetting.HexSend = chk_HexSend.Checked;
                Setting.MySetting.HexShow = chk_HexShow.Checked;
                Setting.NeedSaveSetting = true;
            }
        }

        private void txt_Send_TextChanged(object sender, EventArgs e)
        {
            if (SettingLoadOK == true)
            {
                Setting.NeedSaveSetting = true;
            }
        }

        private void btn_ClearRX_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                SendNum = 0;       
                Ssrlbl_SendNum.Text = SendNum.ToString();
            }
        }

        private void 数据收发ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Setting.ShowDialog();
        }

        private void 接收区背景色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)       //如果是只读TXT编辑框，需要先设置背景色，再设置字体颜色才有效
            {
                txt_ShowRX.BackColor = colorDialog1.Color;
                Setting.NeedSaveSetting = true;
            }
        }

        private void 字体和大小ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (fontDialog1.ShowDialog() == DialogResult.OK)
            {
                txt_ShowRX.Font = fontDialog1.Font;
                Setting.NeedSaveSetting = true;
            }
        }

        private void 颜色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (colorDialog1.ShowDialog() == DialogResult.OK)
            {
                txt_ShowRX.ForeColor = colorDialog1.Color;
                Setting.NeedSaveSetting = true;
            }
        }

        private void 恢复默认ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FontConverter fc = new FontConverter();
            txt_ShowRX.Font = (Font)fc.ConvertFromString("Courier New, 12pt");
            txt_ShowRX.ForeColor = Color.Black;
            Setting.NeedSaveSetting = true;
        }      

    }
}
